feat(parser): record-update spread at start #{ ..base, f: v } (Refs gitbot-fleet#148)#376
Merged
Merged
Conversation
… gitbot-fleet#148)
Adds the Rust-style record-update form to `expr_record_body`: a leading
`..spread` followed by COMMA and one or more fields, all inside `#{ ... }`.
The existing grammar accepted:
- empty record `#{}`
- spread-only `#{ ..s }`
- fields with optional trailing spread `#{ f: v, ..s }`
But the Rust-style `Record #{ ..base, override: x }` (spread captures the
source-of-defaults, subsequent fields override) was a parse error.
Required by sustainabot hand-port (gitbot-fleet#148):
- `Model #{ ..model, totalProcessed: n }` in Oikos.affine
- `Router #{ ..router, routes: rs }` in Router.affine
LR(1)-safe: after parsing `expr_record_spread`, the lookahead is either
RBRACE (the existing spread-only rule reduces) or COMMA (this new rule
shifts); the choice is unambiguous on one-token lookahead. Parser builds
with 21 shift/reduce + 1 reduce/reduce, identical to the pre-patch
baseline.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 41 issues detected
View findings[
{
"reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Action actions/checkout@v6 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action denoland/setup-deno@v2 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/discover.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/packages/affine-js/types.d.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
hyperpolymath
added a commit
to hyperpolymath/gitbot-fleet
that referenced
this pull request
May 26, 2026
…Refs #148) (#206) ## Summary Two hand-port corrections after re-validating sustainabot's ReScript→AffineScript files against the live `affinescript check`: 1. **OCaml-style float operators** `/.`, `*.`, `+.`, `-.` → AffineScript `/`, `*`, `+`, `-`. AffineScript uses unified arithmetic operators for Int and Float (see `examples/lessons/01_hello.affine`: `subtotal * 0.08`), so the OCaml separation was a hand-port artefact. Affected: `GitHubApp.affine`, `Oikos.affine`, `Report.affine`. 2. **`handle` is a contextual keyword** in AffineScript (HANDLE token, used in `handle body { handlers }` effect expressions), so it cannot be a function name. Renamed `Router.affine`'s `pub fn handle(...)` → `pub fn dispatch(...)`. The function dispatches a request to its matching route handler — the rename is also more accurate. ## Gate This PR's parse-time fix is fully effective only once the four parser PRs gated on the same issue have merged: - hyperpolymath/affinescript#370 (trailing-comma in fn params + expr lists + effect-annotated lambda) - hyperpolymath/affinescript#371 (fn-type with effect arrow in type position) - hyperpolymath/affinescript#372 (builtin/lowercase qualified paths + TOTAL field name) - hyperpolymath/affinescript#373 (underscore-prefix idents `_key`/`_unused`) - hyperpolymath/affinescript#376 (record-update spread at start) ## Test plan - [x] After landing the 5 affinescript PRs + this PR: `affinescript check` on all 13 sustainabot `.affine` files reaches at least Resolution (no parse errors). 12 hit `Resolve.UndefinedModule` (stdlib not loaded by the check), 1 (`tea/Sub.affine`) hit it from the start. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 41 issues detected
View findings[
{
"reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Action actions/checkout@v6 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action denoland/setup-deno@v2 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/discover.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/packages/affine-js/types.d.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the Rust-style record-update form to
expr_record_body: a leading..spreadfollowed by COMMA and one or more fields, all inside#{ ... }.The existing grammar accepted:
#{}#{ ..s }#{ f: v, ..s }But the Rust-style
Record #{ ..base, override: x }was a parse error. Required by sustainabot hand-port (gitbot-fleet#148):Model #{ ..model, totalProcessed: n }in Oikos.affineRouter #{ ..router, routes: rs }in Router.affineConflict cost
Zero. LR(1)-safe: after parsing
expr_record_spread, the lookahead is either RBRACE (the existing spread-only rule reduces) or COMMA (this new rule shifts); the choice is unambiguous on one-token lookahead. Parser builds with 21 shift/reduce + 1 reduce/reduce, identical to the pre-patch baseline.Test plan
dune build bin/main.exe— cleanmenhir --explain— 21 S/R + 1 R/R (unchanged)_key/_unused(Refs gitbot-fleet#148) #373, all 13 sustainabot.affinefiles reach Resolution (no parse errors)🤖 Generated with Claude Code